package com.mimo.comet.provider;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.mimo.comet.dao.ISessionDao;
import com.mimo.comet.provider.command.BaseCommand;
import com.mimo.comet.provider.command.CommandType;
import com.mimo.comet.provider.command.echo.AckEchoCommand;
import com.mimo.comet.provider.command.echo.BaseEchoCommand;
import com.mimo.comet.provider.command.echo.EchoType;
import com.mimo.common.utils.JsonUtils;
import com.mimo.common.utils.RandomStringUtils;

@Service
public class DefaultCommandRouterImpl implements ICommandRouter {

  private static final Logger log = LoggerFactory.getLogger(DefaultCommandRouterImpl.class);

  @Autowired
  private ISessionDao sessionDao;

  @SuppressWarnings("rawtypes")
  @Autowired
  private List<ICommandProvider> providers;

  @SuppressWarnings("unchecked")
  @Override
  public Object route(String userId, BaseCommand cmd, Object delegate) {
    if (cmd.isValid()) { // 必须先验证客户端指令的完整性
      Optional<ISession> opt = sessionDao.findByUid(userId);
      if (opt.isPresent()) {
        ISession session = opt.get();
        List<BaseEchoCommand> results = providers.stream()
            .filter(p -> Objects.equals(session.getCometType(), p.getSupportCometType())).filter(p -> p.support(cmd))
            .map(p -> p.process(userId, cmd)).filter(Objects::nonNull)
            .filter(echo -> !Objects.equals(echo.getType(), EchoType.Ack)).collect(Collectors.toList());

        if (!Objects.equals(cmd.getType(), CommandType.Ack)) { // 如果是客户端的正常确认消息,服务端则静默处理
          if (CollectionUtils.isEmpty(results) && !session.isClosed()) {// 如果没有任何响应，则服务器默认返回一个接收确认
            AckEchoCommand ack = new AckEchoCommand();
            ack.setId(RandomStringUtils.uniqueRandom());
            ack.setTarget(cmd.getId());
            session.write(JsonUtils.toJsonString(ack));
          } else {
            results.forEach(echo -> session.write(JsonUtils.toJsonString(echo)));
          }
        }
      } else {
        log.error("userId[{}]没有会话绑定上下文cmd[{}]", userId, cmd);
      }
    }

    return null;
  }

}
